package net.hangar5.xmlrpc;

/* HttpClient.java

The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.

The Original Code is "Hangar5 XMLRPC Library".

The Initial Developer of the Original Code is James D. Rudnicki.
Portions created by James D. Rudnicki are
Copyright (C) 2001.  All Rights Reserved.

Contributor(s):
*/
import java.net.*;
import java.io.*;

/* Yet another HttpClient class.
 * This one is minimized to provide just the functionality needed for the
 * library.
 */
public class HttpClient {

  protected String hostname;
  protected String host;
  protected int port;
  protected String strUriDefault;

  protected Socket socket = null;
  protected BufferedOutputStream output;
  protected BufferedInputStream input;

  protected boolean bKeepAlive;
  protected boolean bConnected;

  protected static final byte[] byPost = "POST ".getBytes();
  protected static final byte[] byPut = "PUT ".getBytes();
  protected static final byte[] byAgent =  "User-Agent: Hangar5 HttpClient\r\n".getBytes();

  /** HTML text/plain type (default) */
  public static final byte[] byText = "Content-Type: text/plain\r\n".getBytes();

  /** HTML text/xml type */
  public static final byte[] byXml = "Content-Type: text/xml\r\n".getBytes();

  protected static final byte[] byContentLength = "Content-Length: ".getBytes();
  protected static final byte[] byHost = "Host: ".getBytes();
  protected static final byte[] byLineEnd = "\r\n".getBytes();

  protected byte[] bySelectType;

  public HttpClient()
  {
  	bySelectType = byText;
	socket = null;
	input = null;
	output = null;
	bConnected = false;
	bKeepAlive = false;
  }


  public HttpClient( URL url ) throws IOException
  {
	hostname = url.getHost ();
	port = url.getPort();
	if (port < 1)
        {
	  port = 80;
	}
	strUriDefault = url.getFile ();
	if( (strUriDefault == null) || ("".equals (strUriDefault)) )
        {
	  strUriDefault = "/";
	}

	host = port == 80 ? hostname : hostname+":"+port;
	bySelectType = byText;
	socket = null;
	input = null;
	output = null;
	bConnected = false;
	bKeepAlive = false;
  }

  public void setUrl(URL url)
  {
     	hostname = url.getHost ();
	port = url.getPort();
	if (port < 1)
        {
	  port = 80;
	}
	strUriDefault = url.getFile ();
	if( (strUriDefault == null) || ("".equals (strUriDefault)) ) {
	  strUriDefault = "/";
	}
	host = port == 80 ? hostname : hostname+":"+port;
  }

  /**
   */
  public void closeConnection()
  {
	try
        {
	  if( bConnected )
          {
		socket.close ();
	  }
	}
	catch( Exception ignore ) {}
	bConnected = false;
	socket = null;
	input = null;
	output = null;
  }

  public boolean getKeepAlive()
  {
	return bKeepAlive;
  }

  /** Create and return a response object.
   * Note that the response is created from the output stream and can only
   * be got once.  Subsequent calls to this method on the same write___ will
   * return a null value.
   * If the connection to the server is not keep-alive
   * then the connection will be closed.
   */
  public HttpResponse getResponse()
  {
	HttpResponse hr = null;
	if( null != input )
        {
	  hr = new HttpResponse( input );
	  hr.read();
	  if( !bKeepAlive )
          {
		closeConnection();
	  }
	}
	return hr;
  }

  public BufferedInputStream getResponseStream()
  {
	return input;
  }
  public String getUri()
  {
	return strUriDefault;
  }

  /** Open the stream
   */
  public void initConnection() throws IOException
  {
	try
        {
	  if( bConnected )
          {
		closeConnection();
	  }
	  socket = new Socket (hostname, port);
	  output = new BufferedOutputStream (socket.getOutputStream());
	  input = new BufferedInputStream (socket.getInputStream ());
	  bConnected = true;
	}
	catch( IOException x )
        {
	  bConnected = false;
	  throw x;
	}
	return;
  }
  /** Set HTML content type
   * @param byNew is string to send.  Use one of provided types:
   * byText, byXml... */
  public void setContentType( byte[] byNew )
  {
	bySelectType = byNew;
	return;
  }
  public void setKeepAlive( boolean bNew )
  {
	bKeepAlive = bNew;
  }
  /** Change the default URI.
   */
  public void setUri( String strNew )
  {
	strUriDefault = strNew;
	if( (strUriDefault == null) || ("".equals (strUriDefault)) )
        {
	  strUriDefault = "/";
	}
  }
  /** Write content via POST to default URI
   */
  public void writePost( byte[] request ) throws IOException
  {
	writePost( strUriDefault, request );
  }
  /** Write content via POST to specified URI.
   * This does not change the default URI.
   */
  public void writePost( String strUri, byte[] request ) throws IOException
  {
	if( null==strUri )
        {
	  writeRequest( byPost, strUriDefault, request );
	}
	else
        {
	  writeRequest( byPost, strUri, request );
	}
  }
  /** Write content via PUT to default URI
   */
  public void writePut( byte[] request ) throws IOException
  {
	writePut( strUriDefault, request );
  }
  /** Write content via PUT to specified URI.
   * This does not change the default URI.
   */
  public void writePut( String strUri, byte[] request ) throws IOException
  {
	if( null==strUri )
        {
	  writeRequest( byPut, strUriDefault, request );
	}
	else
        {
	  writeRequest( byPut, strUri, request );
	}
  }

  protected void writeRequest( byte[] byType, String strUri, byte[] request ) throws IOException
  {
	try
        {
	  if( !bConnected )
          {
		initConnection();
	  }
	  /* PUT /path/a HTTP/1.0\r\n */
	  output.write( byType );
	  output.write( strUri.getBytes() );
	  output.write( " HTTP/1.0\r\n".getBytes() );
	  output.write( byAgent );
	  /* Host: xyz \r\n */
	  output.write( byHost );
	  output.write( host.getBytes() );
	  output.write( byLineEnd );
	  if( bKeepAlive )
          {
		output.write ("Connection: Keep-Alive\r\n".getBytes());
	  }
	  else
          {
		output.write ( "Connection: Close\r\n".getBytes() );
	  }
	  /* Content-Type: text/xml \r\n */
	  output.write( bySelectType );
	  /* Content-Length: nnnnnn \r\n */
	  output.write( byContentLength );
	  output.write( Integer.toString(request.length).getBytes() );
	  output.write( byLineEnd );
	  /* end of header */
	  output.write( byLineEnd );
	  output.write (request);
	  output.flush ();

	}
        catch (IOException iox)
        {
	  closeConnection();
	  throw (iox);
	}
  }
} // end HttpClient
